Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize QRColorMask apply_mask method for enhanced performance #372

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

smalyu
Copy link

@smalyu smalyu commented Sep 2, 2024

This commit introduces optimizations to the apply_mask method in the QRColorMask class to improve performance. Changes include:

  1. Replacing getpixel and putpixel with direct pixel manipulation using the load() method, which speeds up the process.
  2. Implementing a caching mechanism to reuse color transformations for identical pixel colors, reducing redundant calculations.
  3. Adding conditions to skip processing for background color pixels to reduce computational load.

These optimizations have significantly reduced the method's execution time. In some experiments, these changes have resulted in performance improvements of over ten times compared to the original method, especially for larger images.

This commit introduces optimizations to the apply_mask method in the QRColorMask class to improve performance. Changes include:

1. Replacing getpixel and putpixel with direct pixel manipulation using the load() method, which speeds up the process.
2. Implementing a caching mechanism to reuse color transformations for identical pixel colors, reducing redundant calculations.
3. Adding conditions to skip processing for background color pixels to reduce computational load.

These optimizations have significantly reduced the method's execution time. In some experiments, these changes have resulted in performance improvements of over ten times compared to the original method, especially for larger images.
@smalyu
Copy link
Author

smalyu commented Sep 15, 2024

Hi! Just wanted to follow up on this PR. I believe these changes can significantly improve performance, especially for larger images. Let me know if there's anything that needs to be adjusted or clarified!

@maribedran
Copy link
Contributor

Hi @smalyu! Thank you for this!
I'm helping manage this project, but I don't understand much of the internals of the image processing itself. Can you add an example of how to test this? Looking at the code it seems to be good to go.

@smalyu
Copy link
Author

smalyu commented Oct 3, 2024

Hi @maribedran! Below, I've provided a simple test case that demonstrates the improved performance of the apply_mask method in the QRColorMask class.

This example generates a QR code with custom styles and measures the time it takes to create the image. You can use this code to measure the performance on your system. To compare it with the previous version, you would need to swap in the original apply_mask method and run the test again to see the difference.

import time

import qrcode
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.colormasks import SolidFillColorMask
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer

start_time = time.time()

# Create QR code object with parameters
qr = qrcode.QRCode(
    error_correction=qrcode.constants.ERROR_CORRECT_H,
    box_size=100,
    border=2
)

# Add data to the QR code
qr.add_data(12345678901234567890123456789012345678901234567890)

# Generate the QR code image with custom styles
qr_img = qr.make_image(
    image_factory=StyledPilImage,
    module_drawer=RoundedModuleDrawer(),
    eye_drawer=RoundedModuleDrawer(),
    color_mask=SolidFillColorMask(front_color=(239, 49, 35)),
)

# Save the image
qr_img.save("result.png")

end_time = time.time()

print(f"QR code generation time: {end_time - start_time:.4f} seconds")

On my MacBook Pro M1 Pro 2021, the execution time of the original method was 20.3019 seconds, and with the proposed optimizations, it improved significantly to 1.5854 seconds. You can run this script to verify the performance improvements on your setup and see the impact of the changes firsthand.

Let me know if you need further explanations or additional tests!

@maribedran maribedran mentioned this pull request Oct 3, 2024
… colors

- Resolved cache issues in `apply_mask` by setting `use_cache` to `False` by default, preventing errors in masks where pixel position affects color (e.g., RadialGradientColorMask).
- Enabled `use_cache` for `SolidFillColorMask`, as pixel position is not relevant, preserving performance where applicable.
@smalyu
Copy link
Author

smalyu commented Oct 4, 2024

Hi @maribedran! Thanks for reviewing this.

I realized I hadn't accounted for all use cases of apply_mask initially—apologies for that. This update fixes a cache bug in masks dependent on pixel position (like RadialGradientColorMask) by disabling caching by default. For SolidFillColorMask, where position doesn’t matter, caching is enabled to keep performance optimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants